﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.Windows.Media.Imaging;
using System.Globalization;
using System.Collections;
using System.Windows.Controls;

namespace ResourceBlender_Express.Converters {
    /// <summary>
    /// Converts a list of language codes to a list of <code, englishName>
    /// </summary>
    public class LanguageCodeListConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value == null) return null;
            List<string> codes = value as List<string>;
            ObservableSortedDictionary<string, string> items = new ObservableSortedDictionary<string, string>(new Comparers.DictionaryValueComparer(), new Comparers.StringEqualityComparer());
            string englishName;
            foreach(string code in codes) {
                try {
                    englishName = CultureInfo.GetCultureInfo(code).EnglishName;
                } catch{
                    englishName = code;
                }
                items.Add(code, englishName);
            }
            return items;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Converts a language code to it's english name if the code is supported by GetCultureInfo
    /// </summary>
    public class LanguageCodeConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value == null) return null;
            try {
                return CultureInfo.GetCultureInfo(value.ToString()).EnglishName;
            } catch {
                return value;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }
    
    /// <summary>
    /// Converts a list of language codes to a string containing all codes, sorted by name
    /// </summary>
    public class LanguageCodeListStringifier : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value == null) return null;
            List<string> languageCodes = value as List<string>;
            int numLanguages = languageCodes.Count;
            string[] languageNames = new string[numLanguages];
            for(int i = 0; i < numLanguages; i++) {
                try {
                    languageNames[i] = CultureInfo.GetCultureInfo(languageCodes[i]).EnglishName;
                } catch {
                    languageNames[i] = languageCodes[i];
                }
            }
            Array.Sort(languageNames);
            StringBuilder buffer = new StringBuilder();
            for(int i = 0; i < numLanguages; i++) {
                buffer.Append(languageNames[i]);
                if(i < numLanguages-1) {
                    buffer.Append(", ");
                }
            }
            return buffer.ToString();
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Formats a string displaying duplicate data
    /// Assumes there are two bindings and a parameter, the first is the number of duplicates, the second is the language code, the parameter is the string format
    /// </summary>
    public class DuplicateFormatter : IMultiValueConverter {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
            if(values == null) return null;
            string englishName;
            try {
                englishName = CultureInfo.GetCultureInfo(values[1].ToString()).EnglishName;
            } catch {
                englishName = values[1].ToString();
            }
            return string.Format((parameter ?? string.Empty).ToString(), values[0], englishName);
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Converts a dictionary of bundles to a string, sorted by bundle name
    /// </summary>
    public class BundleNameStringifier : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value == null) return null;
            string[] bundleNames = (value as IDictionary<string, string>).Values.ToArray();
            int numBundles = bundleNames.Length;
            StringBuilder buffer = new StringBuilder();
            for(int i = 0; i < numBundles; i++) {
                buffer.Append(bundleNames[i]);
                if(i < numBundles - 1) {
                    buffer.Append(", ");
                }
            }
            return buffer.ToString();
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }
    
    /// <summary>
    /// Converts a ChangeableBundle.ChangeMode to an image which represnts the mode.
    /// </summary>
    public class ActionToImage : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value == null) return null;
            BitmapImage img = null;
            string imageName = string.Empty;
            if(value is KeyValuePair<string, ChangeableBundle>) {
                switch(((KeyValuePair<string, ChangeableBundle>)value).Value.Mode) {
                    case ChangeableBundle.ChangeMode.None:
                        imageName = "/Resources/images/bundle_16.png";
                        break;
                    case ChangeableBundle.ChangeMode.Add:
                        imageName = "/Resources/images/bundle_add_16.png";
                        break;
                    case ChangeableBundle.ChangeMode.Edit:
                        imageName = "/Resources/images/bundle_edit_16.png";
                        break;
                    case ChangeableBundle.ChangeMode.Delete:
                        imageName = "/Resources/images/bundle_delete_16.png";
                        break;
                }
            }
            try {
                img = new BitmapImage(new Uri(imageName, UriKind.Relative));
            } catch {
                img = new BitmapImage();
            }
            return img;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Returns a boolean value to indicate whether an RBApplication contains at least one bundle and language, making it valid for resource editing.
    /// </summary>
    public class CanEditAppConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            if(value == null) return null;
            RBApplication app = value as RBApplication;
            if(app == null) {
                return false;
            } else {
                return app.Languages.Count > 0 && app.Bundles.Count > 0;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }

    /// <summary>
    /// Calculates the column width required to fill the view in a GridView
    /// </summary>
    public class WidthConverter : IValueConverter {
        /// <summary>
        /// Converts the specified value.
        /// </summary>
        /// <param name="value">The parent Listview.</param>
        /// <param name="type">The type.</param>
        /// <param name="parameter">
        /// If no parameter is given, the remaning with will be returned.
        /// If the parameter is an integer acts as MinimumWidth, the remaining with will be returned only if it's greater than the parameter
        /// If the parameter is anything else, it's taken to be a percentage. Eg: 0.3* = 30%, 0.15* = 15%
        /// </param>
        /// <param name="culture">The culture.</param>
        /// <returns>The width, as calculated by the parameter given</returns>
        public object Convert(object value, Type type, object parameter, CultureInfo culture) {
            if(value == null) return null;
            ListView listView = value as ListView;
            GridView grdView = listView.View as GridView;
            int minWidth = 0;
            bool widthIsPercentage = parameter != null && !int.TryParse(parameter.ToString(), out minWidth);
            if(widthIsPercentage) {
                string widthParam = parameter.ToString();
                double percentage = double.Parse(widthParam.Substring(0, widthParam.Length - 1));
                return listView.ActualWidth * percentage;
            } else {
                double total = 0;
                for(int i = 0; i < grdView.Columns.Count - 1; i++) {
                    total += grdView.Columns[i].ActualWidth;
                }
                double remainingWidth = listView.ActualWidth - total;
                if(remainingWidth > minWidth) { // fill the remaining width in the ListView
                    return remainingWidth;
                } else { // fill remaining space with MinWidth
                    return minWidth;
                }
            }            
        }

        public object ConvertBack(object o, Type type, object parameter, CultureInfo culture) {
            throw new NotSupportedException();
        }
    }

    /// <summary>
    /// Provides a breakpoint for debugging
    /// </summary>
    public class DebugConverter : IValueConverter {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
            return value;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
            throw new NotImplementedException();
        }
    }
}
